package common;

import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 数字转人民币大写 @see common.FormatMoney#convertCurrency(java.lang.String)
 * 人民币大写转数字 @see common.FormatMoney#getFormatMoney(java.lang.String)
 *
 * @author K
 * @date 2022-01-24 9:36
 */
public class FormatMoney {

    private FormatMoney() {
    }

    //无效字符
    private static final Pattern INVALID_CHARACTER = Pattern.compile("[^,.\\d]");
    //有效数字格式
    private static final Pattern VALID_DIGIT = Pattern
            .compile("^((\\d{1,3}(,\\d{3})*(.((\\d{3},)*\\d{1,3}))?)|(\\d+(.\\d+)?))$");
    //最大值999亿多
    private static final double MAXIMUM_NUMBER = 99999999999.99;
    //货币符号
    private static final String CN_ZERO = "零";
    private static final String CN_ONE = "壹";
    private static final String CN_TWO = "贰";
    private static final String CN_THREE = "叁";
    private static final String CN_FOUR = "肆";
    private static final String CN_FIVE = "伍";
    private static final String CN_SIX = "陆";
    private static final String CN_SEVEN = "柒";
    private static final String CN_EIGHT = "捌";
    private static final String CN_NINE = "玖";
    private static final String CN_TEN = "拾";
    private static final String CN_HUNDRED = "佰";
    private static final String CN_THOUSAND = "仟";
    private static final String CN_TEN_THOUSAND = "万";
    private static final String CN_HUNDRED_MILLION = "亿";
    private static final String CN_DOLLAR = "元";
    private static final String CN_TEN_CENT = "角";
    private static final String CN_CENT = "分";
    private static final String CN_INTEGER = "整";
    //整数 0-9
    private static final String[] DIGITS = {
            CN_ZERO, CN_ONE, CN_TWO, CN_THREE, CN_FOUR, CN_FIVE, CN_SIX, CN_SEVEN, CN_EIGHT, CN_NINE};
    //基数 百 千
    private static final String[] RADICES = {"", CN_TEN, CN_HUNDRED, CN_THOUSAND};
    //大基数 万 亿
    private static final String[] BIGRADICES = {"", CN_TEN_THOUSAND, CN_HUNDRED_MILLION};
    //小数 角 分
    private static final String[] DECIMALS = {CN_TEN_CENT, CN_CENT};


    /**
     * 数字转人民币大写
     * 支持十亿单位
     */
    private static String convertCurrency(String currencyDigits) {
        if (currencyDigits == null || currencyDigits.length() == 0) {
            System.out.println("不能为空");
            return "";
        }
        //字符串中不能包含除了逗号点号和数字的其他字符
        if (INVALID_CHARACTER.matcher(currencyDigits).matches()) {
            System.out.println("包含无效字符");
            return "";
        }
        if (!VALID_DIGIT.matcher(currencyDigits).matches()) {
            System.out.println("数字格式错误");
            return "";
        }
        //移除所有的逗号
        currencyDigits = currencyDigits.replaceAll(",", "");
        //移除所有的前导零
        currencyDigits = currencyDigits.replaceAll("^0+", "");
        // Assert the number is not greater than the maximum number.
        if (Double.parseDouble(currencyDigits) > MAXIMUM_NUMBER) {
            return "";
        }
        //根据点号分割成两部分整数和小数
        String[] parts = currencyDigits.split("\\.");
        //整数
        String integral;
        //小数
        String decimal;
        if (parts.length > 1) {
            integral = parts[0];
            decimal = parts[1];
            //小数最多保留2位
            if (decimal.length() >= 2) {
                decimal = decimal.substring(0, 2);
            } else {
                decimal = decimal.substring(0, 1);
            }
        } else {
            integral = parts[0];
            decimal = "";
        }
        StringBuilder outputCharacters = new StringBuilder();
        //处理整数
        if (Integer.parseInt(integral) > 0) {
            int zeroCount = 0;
            for (int i = 0; i < integral.length(); i++) {
                int p = integral.length() - i - 1;
                int d = integral.charAt(i) - '0';
                int quotient = p / 4;
                int modulus = p % 4;
                if (d == 0) {
                    zeroCount++;
                } else {
                    if (zeroCount > 0) {
                        outputCharacters.append(DIGITS[0]);
                    }
                    zeroCount = 0;
                    outputCharacters.append(DIGITS[d]).append(RADICES[modulus]);
                }
                if (modulus == 0 && zeroCount < 4) {
                    outputCharacters.append(BIGRADICES[quotient]);
                }
            }
            outputCharacters.append(CN_DOLLAR);
        }
        //处理小数
        if (!decimal.isEmpty()) {
            for (int i = 0; i < decimal.length(); i++) {
                int d = decimal.charAt(i) - '0';
                int ds = decimal.charAt(decimal.length() - 1) - '0';
                if (d == 0) {
                    if (ds != 0) {
                        outputCharacters.append(DIGITS[d]);
                    }
                } else {
                    outputCharacters.append(DIGITS[d]).append(DECIMALS[i]);
                }
            }
        }
        if (outputCharacters.length() == 0) {
            outputCharacters.append(CN_ZERO).append(CN_DOLLAR);
        }
        if (decimal.isEmpty()) {
            outputCharacters.append(CN_INTEGER);
        }
        return outputCharacters.toString();
    }


    public static void main(String[] args) {
        //支持十亿单位
        String temp = convertCurrency("1803085555");
        String result = getFormatMoney(temp);
        String result2 = getFormatMoney("100万元");
        String result3 = getFormatMoney("200万美元");
        String result4 = getFormatMoney("A156");
        System.out.println();
    }

    /**
     * 获取格式化后的钱
     * CNY100 100万人民币
     * USD100 100万美元
     */
    public static String getFormatMoney(String str) {
        if (containsLetter(str)) {
            return "";
        }

        String result;
        String money;
        String numbers = getNumbers(str);
        if (numbers != null && numbers.length() > 0) {
            money = numbers;
        } else {
            money = convert(str);
        }

        if (str.contains("美元")) {
            result = "USD" + money;
        } else {
            result = "CNY" + money;
        }

        return result;
    }

    /**
     * 判断字符串中是否包含字母
     */
    public static boolean containsLetter(String str) {
        String regex = ".*[a-zA-Z]+.*";
        Matcher m = Pattern.compile(regex).matcher(str);
        return m.matches();
    }

    /**
     * 截取数字
     * 读取字符串中第一个连续的字符串，不包含后面不连续的数字
     */
    public static String getNumbers(String content) {
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            return matcher.group(0);
        }
        return "";
    }

    /**
     * 截取非数字
     */
    public static String splitNotNumber(String content) {
        Pattern pattern = Pattern.compile("\\D+");
        Matcher matcher = pattern.matcher(content);
        while (matcher.find()) {
            return matcher.group(0);
        }
        return "";
    }

    /**
     * 大写人民币转数字
     * 单位 万元
     */
    public static String convert(String str) {
        Long calculate = calculate(str);
        return calculate / 10000 + "";
    }

    /**
     * 大写人民币转数字 精确到个位数
     */
    public static Long calculate(String str) {
        long result = 0;
        boolean bigNum = false;

        Stack<Long> stack = new Stack<>();
        Stack<Long> bigStack = new Stack<>();
        for (int i = 0; i < str.length(); i++) {
            char charAt = str.charAt(i);
            String cur = String.valueOf(charAt);
            Integer digit = getDigit(cur);
            if (digit != null) {
                stack.push(Long.valueOf(digit));
            } else {
                Long base = getBase(cur);
                if (base == null) {
                    continue;
                }
                //万 亿单位，重新累加
                if (base == 100000000L) {
                    Long bigSum = accumulate(stack, base);
                    bigStack.push(bigSum);
                    continue;
                } else if(base == 10000L){
                    Long sum = accumulate(stack, base);
                    stack.push(sum);
                    continue;
                }

                Long value = stack.pop();
                stack.push(base * value);
            }
        }

        while (!stack.isEmpty()) {
            result += stack.pop();
        }
        while (!bigStack.isEmpty()) {
            result += bigStack.pop();
        }

        return result;
    }

    public static Long accumulate(Stack<Long> stack, Long unit) {
        long sum = 0;
        while (!stack.isEmpty()) {
            sum += stack.pop();
        }
        return sum * unit;
    }

    public static Integer getDigit(String digit) {
        for (int i = 0; i < DIGITS.length; i++) {
            if (DIGITS[i].equals(digit)) {
                return i;
            }
        }
        return null;
    }

    public static Long getBase(String radice) {
        switch (radice) {
            case "拾":
                return 10L;
            case "佰":
                return 100L;
            case "仟":
                return 1000L;
            case "万":
                return 10000L;
            case "亿":
                return 100000000L;
            default:
                return null;
        }
    }

}
